Grup, Grup İşaretçisi, Üye, Üye İşaretçisi
Özet
- 'token grupları' genellikle NFT koleksiyonlarını gerçekleştirmek için kullanılır.
grup işaretçisi
uzantısı, token mintinde grup hesap bilgilerini tutmak için bir grup hesabı ayarlar.grup
uzantısı, grup verilerini mintin kendisi içinde saklamamıza olanak tanır.üye işaretçisi
uzantısı, token mintinde, bir grup içindeki token üyeliğine ilişkin bilgileri tutmak için bireysel bir üye hesabı ayarlar.üye
uzantısı, üye verilerini mintin kendisi içinde saklamamıza olanak tanır.
Genel Bakış
SPL tokenları yalnız başına değerli olsa da, ek işlevsellik için birleştirilebilir. Bunu grup
, grup işaretçisi
, üye
ve üye işaretçisi
uzantılarını birleştirerek Token Extensions Programı'nda yapabiliriz. Bu uzantıların en yaygın kullanım durumu, bir NFT koleksiyonu oluşturmaktır.
Bir NFT koleksiyonu oluşturmak için iki parçaya ihtiyacımız var: "koleksiyon" NFT'si ve koleksiyonun içindeki tüm NFT'ler. Bunu tamamen token uzantıları kullanarak yapabiliriz. "Koleksiyon" NFT'si tek bir mint olabilir ve metadata
, metadata pointer
, grup
ve grup işaretçisi
uzantılarını birleştirebiliriz. Ardından koleksiyon içindeki her bir bireysel NFT, metadata
, metadata pointer
, üye
ve üye işaretçisi
uzantılarını birleştiren bir mint dizisi olabilir.
NFT koleksiyonları yaygın bir kullanım durumu olmasına rağmen, gruplar ve üyeler herhangi bir token türüne uygulanabilir.
grup işaretçisi
ile grup
arasındaki hızlı bir not. grup işaretçisi
uzantısı, herhangi bir on-chain hesabın adresini Token-Grup Arayüzüne işaret etmek üzere saklar. grup
uzantısı ise Token-Grup Arayüzü verilerini doğrudan mint hesabında saklar. Genellikle, grup işaretçisi
doğrudan mintin kendisine işaret eder. üye işaretçisi
ile üye
için de aynı durum geçerlidir, ancak üye verileri ile.
NOT: Bir grubun birçok üyesi olabilir, ancak bir üye yalnızca bir gruba ait olabilir.
Grup ve Grup İşaretçisi
grup
ve grup işaretçisi
uzantıları, bir token grubunu tanımlar. On-chain verisi aşağıdaki gibidir:
update_authority
: Grubu güncellemek için imza atabilen yetki.mint
: Grup tokeninin minti.size
: Mevcut grup üye sayısı.max_size
: Grup için maksimum üye sayısı.
type OptionalNonZeroPubkey = Pubkey; // Tüm sıfırsa, `None` olarak yorumlanır
type PodU32 = [u8; 4];
type Pubkey = [u8; 32];
/// Tip belirleyici: [214, 15, 63, 132, 49, 119, 209, 40]
/// `hash("spl_token_group_interface:group")` ifadesinin ilk 8 byte'ı
pub struct TokenGroup {
/// Grubu güncellemek için imza atabilen yetki
pub update_authority: OptionalNonZeroPubkey,
/// Spoofing'e karşı, grubun belirli bir mint'e ait olduğundan emin olmak için kullanılan mint
pub mint: Pubkey,
/// Mevcut grup üye sayısı
pub size: PodU32,
/// Grup için maksimum üye sayısı
pub max_size: PodU32,
}
Grup ve Grup İşaretçisi ile Mint Oluşturma
grup
ve grup işaretçisi
ile bir mint oluşturmak dört talimat içerir:
SystemProgram.createAccount
createInitializeGroupPointerInstruction
createInitializeMintInstruction
createInitializeGroupInstruction
İlk talimat SystemProgram.createAccount
, blockchain üzerinde mint hesabı için alan ayırır. Ancak, tüm Token Extensions Programı mintleri gibi, mintin boyutunu ve maliyetini hesaplamamız gerekir. Bu, getMintLen
ve getMinimumBalanceForRentExemption
kullanılarak gerçekleştirilebilir. Bu durumda, yalnızca ExtensionType.GroupPointer
ile getMintLen
çağrısı yapacağız. Ardından grup verileri için mint uzunluğuna TOKEN_GROUP_SIZE
ekleyeceğiz.
Mint uzunluğunu almak ve hesap oluşturma talimatı oluşturmak için şunları yapın:
// mint uzunluğunu al
const extensions = [ExtensionType.GroupPointer];
const mintLength = getMintLen(extensions) + TOKEN_GROUP_SIZE;
const mintLamports =
await connection.getMinimumBalanceForRentExemption(mintLength);
const createAccountInstruction = SystemProgram.createAccount({
fromPubkey: payer.publicKey,
newAccountPubkey: mintKeypair.publicKey,
space: mintLength,
lamports: mintLamports,
programId: TOKEN_2022_PROGRAM_ID,
});
İkinci talimat createInitializeGroupPointerInstruction
, grup işaretçisini başlatır. Mint, grup adresini ayarlayabilecek opsiyonel yetki, grubu tutan adres ve sahibi programı argüman olarak alır.
const initializeGroupPointerInstruction =
createInitializeGroupPointerInstruction(
mintKeypair.publicKey,
payer.publicKey,
mintKeypair.publicKey,
TOKEN_2022_PROGRAM_ID,
);
Üçüncü talimat createInitializeMintInstruction
, minti başlatır.
const initializeMintInstruction = createInitializeMintInstruction(
mintKeypair.publicKey,
decimals,
payer.publicKey,
payer.publicKey,
TOKEN_2022_PROGRAM_ID,
);
Dördüncü talimat createInitializeGroupInstruction
, aslında grubu başlatır ve grup hesabında konfigürasyonu saklar.
const initializeGroupInstruction = createInitializeGroupInstruction({
group: mintKeypair.publicKey,
maxSize: maxMembers,
mint: mintKeypair.publicKey,
mintAuthority: payer.publicKey,
programId: TOKEN_2022_PROGRAM_ID,
updateAuthority: payer.publicKey,
});
Son olarak, bu talimatları işlemi ekleyip Solana ağına gönderiyoruz.
const mintTransaction = new Transaction().add(
createAccountInstruction,
initializeGroupPointerInstruction,
initializeMintInstruction,
initializeGroupInstruction,
);
const signature = await sendAndConfirmTransaction(
connection,
mintTransaction,
[payer, mintKeypair],
{ commitment: "finalized" },
);
Grup Yetkisini Güncelleme
Bir grubun yetkisini güncellemek için sadece tokenGroupUpdateGroupAuthority
fonksiyonuna ihtiyacımız var.
import { tokenGroupUpdateGroupAuthority } from "@solana/spl-token";
const signature = await tokenGroupUpdateGroupAuthority(
connection, // bağlantı - Kullanılacak bağlantı
payer, // payer - İşlem ücretleri için ödeyici
mint.publicKey, // mint - Grup mint
oldAuthority, // hesap - Eski güncelleme yetkisinin genel anahtarı
newAuthority, // hesap - Yeni güncelleme yetkisinin genel anahtarı
undefined, // multiSigners - `authority` çok imzalıysa imzalama hesapları
{ commitment: "finalized" }, // confirmOptions - İşlemi onaylamak için seçenekler
TOKEN_2022_PROGRAM_ID, // programId - SPL Token program hesabı
);
Bir Grubun Maksimum Boyutunu Güncelleme
Bir grubun maksimum boyutunu güncellemek için sadece tokenGroupUpdateGroupMaxSize
fonksiyonuna ihtiyacımız var.
import { tokenGroupUpdateGroupMaxSize } from "@solana/spl-token";
const signature = tokenGroupUpdateGroupMaxSize(
connection, // bağlantı - Kullanılacak bağlantı
payer, // payer - İşlem ücretleri için ödeyici
mint.publicKey, // mint - Grup mint
updpateAuthority, // hesap - Grubun güncelleme yetkisi
4, // maxSize - Grubun yeni maksimum boyutu
undefined, // multiSigners - `authority` çok imzalıysa imzalama hesapları
{ commitment: "finalized" }, // confirmOptions - İşlemi onaylamak için seçenekler
TOKEN_2022_PROGRAM_ID, // programId - SPL Token program hesabı
);
Üye ve Üye İşaretçisi
üye
ve üye işaretçisi
uzantıları, bir token üyesini tanımlar. On-chain verisi aşağıdaki gibidir:
mint
: Üye tokeninin minti.grup
: Grup hesabının adresi.üye_numarası
: Üye numarası (grup içindeki indeks).
/// Tip belirleyici: [254, 50, 168, 134, 88, 126, 100, 186]
/// `hash("spl_token_group_interface:member")` ifadesinin ilk 8 byte'ı
pub struct TokenGroupMember {
/// Spoofing'e karşı, üyenin belirli bir mint'e ait olduğundan emin olmak için kullanılan mint
pub mint: Pubkey,
/// `TokenGroup`'un genel anahtarı
pub group: Pubkey,
/// Üye numarası
pub member_number: PodU32,
}
Üye İşaretçisi ile Mint Oluşturma
üye işaretçisi
ve üye
uzantıları ile bir mint oluşturmak dört talimat içerir:
SystemProgram.createAccount
createInitializeGroupMemberPointerInstruction
createInitializeMintInstruction
createInitializeMemberInstruction
İlk talimat SystemProgram.createAccount
, blockchain üzerinde mint hesabı için alan ayırır. Ancak, tüm Token Extensions Programı mintleri gibi, mintin boyutunu ve maliyetini hesaplamamız gerekir. Bu, getMintLen
ve getMinimumBalanceForRentExemption
kullanılarak gerçekleştirilebilir. Bu durumda, ExtensionType.GroupMemberPointer
ile getMintLen
çağrısı yapacağız. Ardından, üye verileri için mint uzunluğuna TOKEN_GROUP_MEMBER_SIZE
ekleyeceğiz.
Mint uzunluğunu almak ve hesap oluşturma talimatı oluşturmak için şunları yapın:
// mint uzunluğunu al
const extensions = [ExtensionType.GroupMemberPointer];
const mintLength = getMintLen(extensions) + TOKEN_GROUP_MEMBER_SIZE;
const mintLamports =
await connection.getMinimumBalanceForRentExemption(mintLength);
const createAccountInstruction = SystemProgram.createAccount({
fromPubkey: payer.publicKey,
newAccountPubkey: mintKeypair.publicKey,
space: mintLength,
lamports: mintLamports,
programId: TOKEN_2022_PROGRAM_ID,
});
İkinci talimat createInitializeGroupMemberPointerInstruction
, grup üye işaretçisini başlatır. Mint, grup adresini ayarlayabilecek opsiyonel yetki, grubu tutan adres ve sahibi programı argüman olarak alır.
const initializeGroupMemberPointerInstruction =
createInitializeGroupMemberPointerInstruction(
mintKeypair.publicKey,
payer.publicKey,
mintKeypair.publicKey,
TOKEN_2022_PROGRAM_ID,
);
Üçüncü talimat createInitializeMintInstruction
, minti başlatır.
const initializeMintInstruction = createInitializeMintInstruction(
mintKeypair.publicKey,
decimals,
payer.publicKey,
payer.publicKey,
TOKEN_2022_PROGRAM_ID,
);
Dördüncü talimat createInitializeMemberInstruction
, aslında üyeyi başlatır ve üye hesabında konfigürasyonu saklar. Bu işlev grup adresini argüman olarak alır ve üyeyi o grupla ilişkilendirir.
const initializeMemberInstruction = createInitializeMemberInstruction({
group: groupAddress,
groupUpdateAuthority: payer.publicKey,
member: mintKeypair.publicKey,
memberMint: mintKeypair.publicKey,
memberMintAuthority: payer.publicKey,
programId: TOKEN_2022_PROGRAM_ID,
});
Son olarak, bu talimatları işlemi ekleyip Solana ağına gönderiyoruz.
const mintTransaction = new Transaction().add(
createAccountInstruction,
initializeGroupMemberPointerInstruction,
initializeMintInstruction,
initializeMemberInstruction,
);
const signature = await sendAndConfirmTransaction(
connection,
mintTransaction,
[payer, mintKeypair],
{ commitment: "finalized" },
);
Grup ve Üye Verilerini Alma
Grup İşaretçisi Durumunu Alma
Bir mint için grup işaretçisi
durumunu almak için, önce getMint
kullanarak hesabı elde etmemiz ve ardından bu veriyi getGroupPointerState
fonksiyonu ile ayrıştırmamız gerekir. Bu, bize GroupPointer
yapısını döndürür.
/** Program tarafından saklanan GroupPointer */
export interface GroupPointer {
/** Grup adresini ayarlayabilen opsiyonel yetki */
authority: PublicKey | null;
/** Grubu tutan opsiyonel hesap adresi */
groupAddress: PublicKey | null;
}
GroupPointer
verilerini almak için şu şekilde çağırın:
const groupMint = await getMint(
connection,
mint,
"confirmed",
TOKEN_2022_PROGRAM_ID,
);
const groupPointerData: GroupPointer = getGroupPointerState(groupMint);
Grup durumunu alma
Bir mint için grup durumunu almak için, önce getMint
kullanarak hesabı elde etmemiz ve ardından bu veriyi getTokenGroupState
fonksiyonu ile ayrıştırmamız gerekir. Bu, TokenGroup
yapısını döndürür.
export interface TokenGroup {
/** Grubu güncellemek için imza atabilen yetki */
updateAuthority?: PublicKey;
/** Spoofing'e karşı, grubun belirli bir mint'e ait olduğundan emin olmak için kullanılan mint */
mint: PublicKey;
/** Mevcut grup üye sayısı */
size: number;
/** Grup için maksimum üye sayısı */
maxSize: number;
}
TokenGroup
verilerini almak için şu şekilde çağırın:
const groupMint = await getMint(
connection,
mint,
"confirmed",
TOKEN_2022_PROGRAM_ID,
);
const groupData: TokenGroup = getTokenGroupState(groupMint);
Grup Üye İşaretçisi Durumunu Alma
Bir mint için üye işaretçisi
durumunu almak için, minti getMint
ile elde ederiz ve ardından getGroupMemberPointerState
ile ayrıştırırız. Bu, bize GroupMemberPointer
yapısını döndürür.
/** Program tarafından saklanan GroupMemberPointer */
export interface GroupMemberPointer {
/** Üye adresini ayarlayabilen opsiyonel yetki */
authority: PublicKey | null;
/** Üyeyi tutan opsiyonel hesap adresi */
memberAddress: PublicKey | null;
}
GroupMemberPointer
verilerini almak için şu şekilde çağırın:
const memberMint = await getMint(
connection,
mint,
"confirmed",
TOKEN_2022_PROGRAM_ID,
);
const memberPointerData = getGroupMemberPointerState(memberMint);
Grup Üye Durumunu Alma
Bir mintin üye
durumunu almak için, minti getMint
ile elde ederiz ve ardından getTokenGroupMemberState
ile ayrıştırırız. Bu, TokenGroupMember
yapısını döndürür.
export interface TokenGroupMember {
/** Spoofing'e karşı, üyenin belirli bir mint'e ait olduğundan emin olmak için kullanılan mint */
mint: PublicKey;
/** `TokenGroup`'un genel anahtarı */
group: PublicKey;
/** Üye numarası */
memberNumber: number;
}
TokenGroupMember
verilerini almak için şu şekilde çağırın:
const memberMint = await getMint(
connection,
mint,
"confirmed",
TOKEN_2022_PROGRAM_ID,
);
const memberData = getTokenGroupMemberState(memberMint);
Laboratuvar
Bu laboratuvarda grup
, grup işaretçisi
, üye
ve üye işaretçisi
uzantılarını metadata
ve metadata pointer
uzantıları ile birlikte kullanarak bir Cool Cats NFT koleksiyonu oluşturacağız.
Cool Cats NFT koleksiyonu, içinde üç üye NFT'si bulunan bir grup NFT'si içerecektir.
1. Başlarken
Başlamak için bu depo starter
dalını klonlayın.
git clone https://github.com/Unboxed-Software/solana-lab-group-member.git
cd solana-lab-group-member
git checkout starter
npm install
starter
kodu şunları içerir:
index.ts
: bir bağlantı nesnesi oluşturur veinitializeKeypair
çağrısını yapar. Burada scriptimizi yazacağız.assets
: NFT koleksiyonumuz için resmi içeren klasör.helper.ts
: metadata yükleme için yardımcı işlevler.
2. Doğrulayıcı düğüm çalıştırma
Bu kılavuz için, kendi doğrulayıcı düğümümüzü çalıştıracağız.
Ayrı bir terminalde, şu komutu çalıştırın: solana-test-validator
. Bu, düğümü çalıştıracak ve bazı anahtarlar ve değerler kaydedecektir. Bağlantımızda kullanmamız gereken değer, bu durumda http://127.0.0.1:8899
olan JSON RPC URL'sidir. Ardından, bununla bağlantıyı kurarak yerel RPC URL'sini kullanmasını belirtiriz.
const connection = new Connection("http://127.0.0.1:8899", "confirmed");
Doğrulayıcı doğru bir şekilde ayarlandığında, index.ts
'yi çalıştırabilir ve her şeyin düzgün çalıştığını onaylayabilirsiniz.
npx esrun src/index.ts
3. Grup metadata ayarları
Grup NFT'mizi oluşturmadan önce grup metadata'sını hazırlayıp yüklememiz gerekir. Görseli ve metadata'yı yüklemek için devnet Irys (Arweave) kullanıyoruz. Bu işlevsellik size helpers.ts
içinde sağlanmaktadır.
Bu dersin kolaylığı için NFT'ler için varlıklar assets
dizininde sağlanmıştır.
Kendi dosyalarınızı ve metadata'nızı kullanmak isterseniz lütfen özgürce kullanabilirsiniz!
Grup metadata'mızı hazırlamak için şunları yapmamız gerekiyor:
- Yükleme için metadata'mızı
LabNFTMetadata
arayüzü kullanarak formatlamak. helpers.ts
içindenuploadOffChainMetadata
çağrısını yapmak.- Önceki adımdan elde edilen uri'yi dahil ederek her şeyi formatlamak.
Yükleme için metadata'mızı formatlamamız gerekiyor (LabNFTMetadata
), resmi ve metadata'yı yüklememiz gerekiyor (uploadOffChainMetadata
), ve nihayet her şeyi @solana/spl-token-metadata
kütüphanesindeki TokenMetadata
arayüzüne formatlamamız gerekiyor.
Not: 100kb altında yüklemeler için devnet Irys kullanıyoruz.
// Grup metadata'sını oluştur
const groupMetadata: LabNFTMetadata = {
mint: groupMintKeypair,
imagePath: "assets/collection.png",
tokenName: "cool-cats-collection",
tokenDescription: "Cool Cat NFT'lerin Koleksiyonu",
tokenSymbol: "MEOW",
tokenExternalUrl: "https://solana.com/",
tokenAdditionalMetadata: {},
tokenUri: "",
};
// Offchain metadata'yı yükle
groupMetadata.tokenUri = await uploadOffChainMetadata(payer, groupMetadata);
// Grup token metadata'sını formatla
const collectionTokenMetadata: TokenMetadata = {
name: groupMetadata.tokenName,
mint: groupMintKeypair.publicKey,
symbol: groupMetadata.tokenSymbol,
uri: groupMetadata.tokenUri,
updateAuthority: payer.publicKey,
additionalMetadata: Object.entries(
groupMetadata.tokenAdditionalMetadata || [],
).map(([trait_type, value]) => [trait_type, value]),
};
Scripti çalıştırmaktan çekinmeyin ve her şeyin yüklendiğinden emin olun.
npx esrun src/index.ts
3. Grup ve grup işaretçisi ile mint oluşturma
metadata
, metadata pointer
, group
ve group pointer
uzantılarını kullanarak grup NFT'sini oluşturalım.
Bu NFT, koleksiyonumuzun görsel temsilidir.
Öncelikle yeni createTokenGroup
fonksiyonumuzun giriş parametrelerini tanımlayalım:
connection
: Blok zincirine bağlantıpayer
: İşlemi ödeyen anahtar çiftimintKeypair
: Mint anahtar çiftidecimals
: Mint ondalık sayıları (NFT'ler için 0)maxMembers
: Grupta izin verilen maksimum üye sayısımetadata
: Grup minti için metadata
export async function createTokenGroup(
connection: Connection,
payer: Keypair,
mintKeypair: Keypair,
decimals: number,
maxMembers: number,
metadata: TokenMetadata,
): Promise<TransactionSignature>;
NFT'mizi oluşturmak için metadata
ve metadata pointer
uzantılarını kullanarak metadata'yı doğrudan mint hesabında saklayacağız. Ayrıca group
ve group pointer
uzantıları ile grup hakkında bazı bilgileri de kaydedeceğiz.
Grup NFT'mizi oluşturmak için aşağıdaki talimatlara ihtiyacımız var:
SystemProgram.createAccount
: Mint hesabı için Solana'da alan tahsis eder.mintLength
vemintLamports
değerlerini sırasıylagetMintLen
vegetMinimumBalanceForRentExemption
kullanarak alabiliriz.createInitializeGroupPointerInstruction
: Grup işaretçisini başlatırcreateInitializeMetadataPointerInstruction
: Metadata işaretçisini başlatırcreateInitializeMintInstruction
: Mint'i başlatırcreateInitializeGroupInstruction
: Grubu başlatırcreateInitializeInstruction
: Metadata'yı başlatır
Son olarak, bu tüm talimatları bir işleme eklememiz ve Solana ağına göndermemiz gerekiyor; ardından imzayı döndüreceğiz. Bunu sendAndConfirmTransaction
çağırarak yapabiliriz.
import {
sendAndConfirmTransaction,
Connection,
Keypair,
SystemProgram,
Transaction,
TransactionSignature,
} from "@solana/web3.js";
import {
ExtensionType,
createInitializeMintInstruction,
getMintLen,
TOKEN_2022_PROGRAM_ID,
createInitializeGroupInstruction,
createInitializeGroupPointerInstruction,
TYPE_SIZE,
LENGTH_SIZE,
createInitializeMetadataPointerInstruction,
TOKEN_GROUP_SIZE,
} from "@solana/spl-token";
import {
TokenMetadata,
createInitializeInstruction,
pack,
} from "@solana/spl-token-metadata";
export async function createTokenGroup(
connection: Connection,
payer: Keypair,
mintKeypair: Keypair,
decimals: number,
maxMembers: number,
metadata: TokenMetadata,
): Promise<TransactionSignature> {
const extensions: ExtensionType[] = [
ExtensionType.GroupPointer,
ExtensionType.MetadataPointer,
];
const metadataLen = TYPE_SIZE + LENGTH_SIZE + pack(metadata).length + 500;
const mintLength = getMintLen(extensions);
const totalLen = mintLength + metadataLen + TOKEN_GROUP_SIZE;
const mintLamports =
await connection.getMinimumBalanceForRentExemption(totalLen);
const mintTransaction = new Transaction().add(
SystemProgram.createAccount({
fromPubkey: payer.publicKey,
newAccountPubkey: mintKeypair.publicKey,
space: mintLength,
lamports: mintLamports,
programId: TOKEN_2022_PROGRAM_ID,
}),
createInitializeGroupPointerInstruction(
mintKeypair.publicKey,
payer.publicKey,
mintKeypair.publicKey,
TOKEN_2022_PROGRAM_ID,
),
createInitializeMetadataPointerInstruction(
mintKeypair.publicKey,
payer.publicKey,
mintKeypair.publicKey,
TOKEN_2022_PROGRAM_ID,
),
createInitializeMintInstruction(
mintKeypair.publicKey,
decimals,
payer.publicKey,
payer.publicKey,
TOKEN_2022_PROGRAM_ID,
),
createInitializeGroupInstruction({
group: mintKeypair.publicKey,
maxSize: maxMembers,
mint: mintKeypair.publicKey,
mintAuthority: payer.publicKey,
programId: TOKEN_2022_PROGRAM_ID,
updateAuthority: payer.publicKey,
}),
createInitializeInstruction({
metadata: mintKeypair.publicKey,
mint: mintKeypair.publicKey,
mintAuthority: payer.publicKey,
name: metadata.name,
programId: TOKEN_2022_PROGRAM_ID,
symbol: metadata.symbol,
updateAuthority: payer.publicKey,
uri: metadata.uri,
}),
);
const signature = await sendAndConfirmTransaction(
connection,
mintTransaction,
[payer, mintKeypair],
);
return signature;
}
Artık fonksiyonumuzu oluşturduğumuza göre, bunu index.ts
dosyamızda çağırabiliriz.
// Grup oluştur
const signature = await createTokenGroup(
connection,
payer,
groupMintKeypair,
decimals,
maxMembers,
collectionTokenMetadata,
);
console.log(
`Metadata ile koleksiyon mint'i oluşturuldu:\n${getExplorerLink("tx", signature, "localnet")}\n`,
);
Scripti çalıştırmadan önce, yeni oluşturulan grup NFT'sini alalım ve içeriğini yazdıralım. Bunu index.ts
dosyasında yapalım:
// Grubu al
const groupMint = await getMint(
connection,
groupMintKeypair.publicKey,
"confirmed",
TOKEN_2022_PROGRAM_ID,
);
const fetchedGroupMetadata = await getTokenMetadata(
connection,
groupMintKeypair.publicKey,
);
const metadataPointerState = getMetadataPointerState(groupMint);
const groupData = getGroupPointerState(groupMint);
console.log("\n---------- GRUP VERİLERİ -------------\n");
console.log("Grup Mint: ", groupMint.address.toBase58());
console.log(
"Metadata Pointer Hesabı: ",
metadataPointerState?.metadataAddress?.toBase58(),
);
console.log("Grup Pointer Hesabı: ", groupData?.groupAddress?.toBase58());
console.log("\n--- METADATA ---\n");
console.log("İsim: ", fetchedGroupMetadata?.name);
console.log("Sembol: ", fetchedGroupMetadata?.symbol);
console.log("Uri: ", fetchedGroupMetadata?.uri);
console.log("\n------------------------------------\n");
Artık scripti çalıştırabiliriz ve oluşturduğumuz grup NFT'sini görebiliriz.
npx esrun src/index.ts
4. Üye NFT Metadata'sını Ayarlama
Artık grup NFT'mizi oluşturduğumuza göre, üye NFT'lerini oluşturabiliriz. Ancak onları gerçekten oluşturmadan önce, metadata'larını hazırlamamız gerekiyor.
Flow, grup NFT ile yaptığımız işlemlerle tamamen aynıdır.
helper.ts
dosyasındanLabNFTMetadata
arayüzünü kullanarak metadata'mızı yüklemeye hazırlamamız gerekiyor.helpers.ts
dosyasındakiuploadOffChainMetadata
fonksiyonunu çağırmalıyız.- Önceki adımdan elde edilen uri'yi
@solana/spl-token-metadata
kütüphanesindekiTokenMetadata
arayüzüne dahil ederek her şeyi formatlamalıyız.
Ancak, üç üyemiz olduğu için, her üye için her adımı döngü ile geçireceğiz.
Öncelikle her üye için metadata'yı tanımlayalım:
// Üye metadata'sını tanımla
const membersMetadata: LabNFTMetadata[] = [
{
mint: cat0Mint,
imagePath: "assets/cat_0.png",
tokenName: "Kedi 1",
tokenDescription: "Sevimli kedi",
tokenSymbol: "MIAU",
tokenExternalUrl: "https://solana.com/",
tokenAdditionalMetadata: {},
tokenUri: "",
},
{
mint: cat1Mint,
imagePath: "assets/cat_1.png",
tokenName: "Kedi 2",
tokenDescription: "Aşırı kedi",
tokenSymbol: "MIAU",
tokenExternalUrl: "https://solana.com/",
tokenAdditionalMetadata: {},
tokenUri: "",
},
{
mint: cat2Mint,
imagePath: "assets/cat_2.png",
tokenName: "Kedi 3",
tokenDescription: "Şaşkın kedi",
tokenSymbol: "MIAU",
tokenExternalUrl: "https://solana.com/",
tokenAdditionalMetadata: {},
tokenUri: "",
},
];
Şimdi, her üye üzerinden döngü ile geçelim ve metadata'larını yükleyelim.
// Üye metadata'sını yükle
for (const member of membersMetadata) {
member.tokenUri = await uploadOffChainMetadata(payer, member);
}
Son olarak, her üyenin metadata'sını TokenMetadata
arayüzüne formatlayalım:
Not: Üye NFT'lerini oluşturmak için anahtar çiftine ihtiyaç duyacağımızdan onu da taşımak isteyeceğiz.
// Token metadata'sını formatla
const memberTokenMetadata: { mintKeypair: Keypair; metadata: TokenMetadata }[] =
membersMetadata.map(member => ({
mintKeypair: member.mint,
metadata: {
name: member.tokenName,
mint: member.mint.publicKey,
symbol: member.tokenSymbol,
uri: member.tokenUri,
updateAuthority: payer.publicKey,
additionalMetadata: Object.entries(
member.tokenAdditionalMetadata || [],
).map(([trait_type, value]) => [trait_type, value]),
} as TokenMetadata,
}));
5. Üye NFT'lerini Oluşturma
Gruplardan oluşan NFT gibi, üye NFT'lerini de oluşturmamız gerekiyor. Bunu create-member.ts
adında yeni bir dosyada yapalım. Bu, create-group.ts
dosyasına oldukça benzer olacaktır; ancak bu sefer group
ve group pointer
uzantıları yerine member
ve member pointer
uzantılarını kullanacağız.
Öncelikle yeni createTokenMember
fonksiyonumuzun giriş parametrelerini tanımlayalım:
connection
: Blok zincirine bağlantıpayer
: İşlemi ödeyen anahtar çiftimintKeypair
: Mint anahtar çiftidecimals
: Mint ondalık sayıları (NFT'ler için 0)metadata
: Grup minti için metadatagroupAddress
: Grup hesabının adresi - bu durumda grup mint'in kendisi
export async function createTokenMember(
connection: Connection,
payer: Keypair,
mintKeypair: Keypair,
decimals: number,
metadata: TokenMetadata,
groupAddress: PublicKey,
): Promise<TransactionSignature>;
Grup NFT gibi, aşağıdaki talimatlara ihtiyacımız var:
SystemProgram.createAccount
: Mint hesabı için Solana'da alan tahsis eder.mintLength
vemintLamports
değerlerini sırasıylagetMintLen
vegetMinimumBalanceForRentExemption
kullanarak alabiliriz.createInitializeGroupMemberPointerInstruction
: Üye işaretçisini başlatırcreateInitializeMetadataPointerInstruction
: Metadata işaretçisini başlatırcreateInitializeMintInstruction
: Mint'i başlatırcreateInitializeMemberInstruction
: Üyeyi başlatırcreateInitializeInstruction
: Metadata'yı başlatır
Son olarak, bu talimatları bir işlemin içine eklememiz, Solana ağına göndermemiz ve imzayı döndürmemiz gerekiyor. Bunu sendAndConfirmTransaction
çağırarak yapabiliriz.
import {
sendAndConfirmTransaction,
Connection,
Keypair,
SystemProgram,
Transaction,
TransactionSignature,
PublicKey,
} from "@solana/web3.js";
import {
ExtensionType,
createInitializeMintInstruction,
getMintLen,
TOKEN_2022_PROGRAM_ID,
TYPE_SIZE,
LENGTH_SIZE,
createInitializeMetadataPointerInstruction,
TOKEN_GROUP_MEMBER_SIZE,
createInitializeGroupMemberPointerInstruction,
createInitializeMemberInstruction,
} from "@solana/spl-token";
import {
TokenMetadata,
createInitializeInstruction,
pack,
} from "@solana/spl-token-metadata";
export async function createTokenMember(
connection: Connection,
payer: Keypair,
mintKeypair: Keypair,
decimals: number,
metadata: TokenMetadata,
groupAddress: PublicKey,
): Promise<TransactionSignature> {
const extensions: ExtensionType[] = [
ExtensionType.GroupMemberPointer,
ExtensionType.MetadataPointer,
];
const metadataLen = TYPE_SIZE + LENGTH_SIZE + pack(metadata).length;
const mintLength = getMintLen(extensions);
const totalLen = mintLength + metadataLen + TOKEN_GROUP_MEMBER_SIZE;
const mintLamports =
await connection.getMinimumBalanceForRentExemption(totalLen);
const mintTransaction = new Transaction().add(
SystemProgram.createAccount({
fromPubkey: payer.publicKey,
newAccountPubkey: mintKeypair.publicKey,
space: mintLength,
lamports: mintLamports,
programId: TOKEN_2022_PROGRAM_ID,
}),
createInitializeGroupMemberPointerInstruction(
mintKeypair.publicKey,
payer.publicKey,
mintKeypair.publicKey,
TOKEN_2022_PROGRAM_ID,
),
createInitializeMetadataPointerInstruction(
mintKeypair.publicKey,
payer.publicKey,
mintKeypair.publicKey,
TOKEN_2022_PROGRAM_ID,
),
createInitializeMintInstruction(
mintKeypair.publicKey,
decimals,
payer.publicKey,
payer.publicKey,
TOKEN_2022_PROGRAM_ID,
),
createInitializeMemberInstruction({
group: groupAddress,
groupUpdateAuthority: payer.publicKey,
member: mintKeypair.publicKey,
memberMint: mintKeypair.publicKey,
memberMintAuthority: payer.publicKey,
programId: TOKEN_2022_PROGRAM_ID,
}),
createInitializeInstruction({
metadata: mintKeypair.publicKey,
mint: mintKeypair.publicKey,
mintAuthority: payer.publicKey,
name: metadata.name,
programId: TOKEN_2022_PROGRAM_ID,
symbol: metadata.symbol,
updateAuthority: payer.publicKey,
uri: metadata.uri,
}),
);
const signature = await sendAndConfirmTransaction(
connection,
mintTransaction,
[payer, mintKeypair],
);
return signature;
}
Yeni fonksiyonumuzu index.ts
dosyasına ekleyelim ve her üye için çağırabiliriz:
// Üye mint'lerini oluştur
for (const memberMetadata of memberTokenMetadata) {
const signature = await createTokenMember(
connection,
payer,
memberMetadata.mintKeypair,
decimals,
memberMetadata.metadata,
groupMintKeypair.publicKey,
);
console.log(
`Oluşturuldu ${memberMetadata.metadata.name} NFT:\n${getExplorerLink("tx", signature, "localnet")}\n`,
);
}
Yeni oluşturduğumuz üye NFT'lerini alalım ve içeriklerini gösterelim.
for (const member of membersMetadata) {
const memberMint = await getMint(
connection,
member.mint.publicKey,
"confirmed",
TOKEN_2022_PROGRAM_ID,
);
const memberMetadata = await getTokenMetadata(
connection,
member.mint.publicKey,
);
const metadataPointerState = getMetadataPointerState(memberMint);
const memberPointerData = getGroupMemberPointerState(memberMint);
const memberData = getTokenGroupMemberState(memberMint);
console.log("\n---------- ÜYE VERİLERİ -------------\n");
console.log("Üye Mint: ", memberMint.address.toBase58());
console.log(
"Metadata Pointer Hesabı: ",
metadataPointerState?.metadataAddress?.toBase58(),
);
console.log("Grup Hesabı: ", memberData?.group?.toBase58());
console.log(
"Üye Pointer Hesabı: ",
memberPointerData?.memberAddress?.toBase58(),
);
console.log("Üye Numarası: ", memberData?.memberNumber);
console.log("\n--- METADATA ---\n");
console.log("İsim: ", memberMetadata?.name);
console.log("Sembol: ", memberMetadata?.symbol);
console.log("Uri: ", memberMetadata?.uri);
console.log("\n------------------------------------\n");
}
Son olarak, scripti çalıştırıp NFT koleksiyonumuzu görebiliriz!
npx esrun src/index.ts
Bu kadar! Sorun yaşıyorsanız, lütfen solution
depo dalına göz atın.
Görev
group
, group pointer
, member
ve member pointer
uzantılarını kullanarak kendi NFT koleksiyonunuzu oluşturun.